home *** CD-ROM | disk | FTP | other *** search
- /*
- * qstat 2.5a
- * by Steve Jankowski
- * steve@qstat.org
- * http://www.qstat.org
- *
- * Copyright 1996,1997,1998,1999 by Steve Jankowski
- *
- * Licensed under the Artistic License, see LICENSE.txt for license terms
- */
-
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <ctype.h>
-
- #include "config.h"
-
- #ifdef __hpux
- #define STATIC static
- #else
- #define STATIC
- #endif
-
- #ifdef _WIN32
- #define strcasecmp stricmp
- #endif
-
-
- #ifdef _WIN32
- #define HOME_CONFIG_FILE "qstat.cfg"
- #else
- #define HOME_CONFIG_FILE ".qstatrc"
- #endif
-
-
- static server_type ** config_types;
- static int n_config_types;
- static int max_config_types;
- static int next_gametype_id= LAST_BUILTIN_SERVER+1;
-
- static int load_config_file( char *filename);
- static int try_load_config_file( char *filename, int show_error);
- static int pf_top_level( char *text, void *context);
- static int pf_gametype_new( char *text, void *context);
- static int pf_gametype_modify( char *text, void *context);
-
- static int set_game_type_value( server_type *gametype, int key, char *value);
- static int modify_game_type_value( server_type *gametype, int key, char *value);
- static int set_packet_value( server_type *gametype, char *value,
- char *packet_name, char **packet, int *len);
-
- static char *first_token( char *text);
- static char *next_token();
- static char *next_token_dup();
- static char *next_value();
- static char * parse_value( char *source, int len);
- static unsigned int parse_hex( char *hex, int len, int *error);
- static unsigned int parse_oct( char *oct, int len, int *error);
- static char *force_lower_case( char *string);
- static char *force_upper_case( char *string);
- static char *get_token();
- static void * memdup( void *mem, unsigned int len);
-
- static int (*parse_func)( char *, void *);
- static void *parse_context;
- static int line;
- static char *current_file_name;
-
- static char *parse_text;
- static char *parse_end;
- static char *lex;
- static char *token_end;
- static char token_buf[1024];
- static int value_len;
-
- static int debug= 0;
-
- #define REPORT_ERROR(a) print_location(); fprintf a; fprintf(stderr, "\n")
-
- #define CK_MASTER_PROTOCOL 1
- #define CK_MASTER_QUERY 2
- #define CK_MASTER_PACKET 3
- #define CK_NAME 4
- #define CK_DEFAULT_PORT 5
- #define CK_GAME_RULE 6
- #define CK_TEMPLATE_VAR 7
- #define CK_MASTER_TYPE 8
- #define CK_STATUS_PACKET 9
- #define CK_STATUS2_PACKET 10
- #define CK_PLAYER_PACKET 11
- #define CK_RULE_PACKET 12
- #define CK_PORT_OFFSET 13
-
-
- typedef struct _config_key {
- int key;
- char *key_name;
- } ConfigKey;
-
- static ConfigKey new_keys[] = {
- { CK_MASTER_PROTOCOL, "master protocol" },
- { CK_MASTER_QUERY, "master query" },
- { CK_MASTER_PACKET, "master packet" },
- { CK_NAME, "name" },
- { CK_DEFAULT_PORT, "default port" },
- { CK_GAME_RULE, "game rule" },
- { CK_TEMPLATE_VAR, "template var" },
- { CK_MASTER_TYPE, "master for gametype" },
- { CK_STATUS_PACKET, "status packet" },
- { CK_STATUS2_PACKET, "status2 packet" },
- { CK_PLAYER_PACKET, "player packet" },
- { CK_RULE_PACKET, "rule packet" },
- { CK_PORT_OFFSET, "status port offset" },
- { 0, NULL },
- };
-
- static ConfigKey modify_keys[] = {
- { CK_MASTER_PROTOCOL, "master protocol" },
- { CK_MASTER_QUERY, "master query" },
- { CK_MASTER_PACKET, "master packet" },
- { 0, NULL },
- };
-
- static int get_config_key( char *first_token, ConfigKey *keys);
- static void add_config_type( server_type *gametype);
- static server_type * get_config_type( char *game_type);
- static void copy_server_type( server_type *dest, server_type *source);
- static server_type * get_server_type( char *game_type);
-
- typedef struct _gametype_context {
- char *type;
- char *extend_type;
- server_type *gametype;
- } GameTypeContext;
-
-
- static void
- print_location()
- {
- fprintf( stderr, "%s line %d: ", current_file_name, line);
- }
-
- int
- qsc_load_default_config_files()
- {
- int rc= 0;
- char *filename= NULL, *var;
- char path[1024];
-
- var= getenv( "QSTAT_CONFIG");
- if ( var != NULL && var[0] != '\0') {
- rc= try_load_config_file( var, 1);
- if ( rc == 0 || rc == -1)
- return rc;
- }
-
- var= getenv( "HOME");
- if ( var != NULL && var[0] != '\0') {
- sprintf( path, "%s/%s", var, HOME_CONFIG_FILE);
- rc= try_load_config_file( path, 0);
- if ( rc == 0 || rc == -1)
- return rc;
- }
-
- #ifdef sysconfdir
- strcpy( path, sysconfdir "/qstat.cfg");
- filename= path;
- #elif defined(_WIN32)
- if ( filename == NULL && _pgmptr && strchr( _pgmptr, '\\')) {
- char *slash= strrchr( _pgmptr, '\\');
- strncpy( path, _pgmptr, slash - _pgmptr);
- path[slash - _pgmptr]= '\0';
- strcat( path, "\\qstat.cfg");
- filename= path;
- }
- #endif
-
- if ( filename != NULL) {
- rc= try_load_config_file( filename, 0);
- if ( rc == 0 || rc == -1)
- return rc;
- }
- return rc;
- /*
- if ( rc == -2 && show_error) {
- perror( filename);
- fprintf( stderr, "Error: Could not open config file \"%s\"\n",
- filename);
- }
- else if ( rc == -1 && show_error)
- fprintf( stderr, "Error: Error loading $QSTAT_CONFIG file\n");
- return rc;
- */
-
- #ifdef foo
- filename= getenv( "HOME");
- if ( filename != NULL && filename[0] != '\0') {
- char path[1024];
- sprintf( path, "%s/%s", filename, HOME_CONFIG_FILE);
- }
- /* 1. $QSTAT_CONFIG
- 2. UNIX: $HOME/.qstatrc WIN: $HOME/qstat.cfg
- 3. UNIX: sysconfdir/qstat.cfg WIN: qstat.exe-dir/qstat.cfg
- */
-
- rc= load_config_file( "qstat.cfg");
- if ( rc == -1)
- fprintf( stderr, "Warning: Error loading default qstat.cfg\n");
- return 0;
- #endif
- }
-
- int
- qsc_load_config_file( char *filename)
- {
- int rc= load_config_file( filename);
- if ( rc == -2) {
- perror( filename);
- fprintf( stderr, "Could not open config file \"%s\"\n",
- filename);
- return -1;
- }
- return rc;
- }
-
- server_type **
- qsc_get_config_server_types( int *n_config_types_ref)
- {
- if ( n_config_types_ref)
- *n_config_types_ref= n_config_types;
- return config_types;
- }
-
- STATIC int
- try_load_config_file( char *filename, int show_error)
- {
- int rc= load_config_file( filename);
- if ( rc == -2 && show_error) {
- perror( filename);
- fprintf( stderr, "Error: Could not open config file \"%s\"\n",
- filename);
- }
- else if ( rc == -1)
- fprintf( stderr, "Error: Could not load config file \"%s\"\n",
- filename);
- return rc;
- }
-
- STATIC int
- load_config_file( char *filename)
- {
- FILE *file;
- int rc;
-
- file= fopen( filename, "r");
- if ( file == NULL)
- return -2;
-
- current_file_name= filename;
- rc= parse_config_file( file);
- fclose(file);
- return rc;
- }
-
- int
- parse_config_file( FILE *file)
- {
- char buf[4096];
- int rc;
-
- line= 0;
- parse_func= pf_top_level;
-
- while ( fgets( buf, sizeof(buf), file) != NULL) {
- int len= strlen(buf);
- while ( len && (buf[len-1] == '\n' || buf[len-1] == '\r'))
- len--;
- buf[len]= '\0';
- line++;
- rc= parse_func( buf, parse_context);
- if ( rc != 0)
- return rc;
- }
- return 0;
- }
-
-
- /* Top level
- * Keywords: gametype
- */
- STATIC int
- pf_top_level( char *text, void *_context)
- {
- GameTypeContext *context;
- server_type *extend;
- char *token, *game_type, *extend_type;
- token= first_token( text);
- if ( token == NULL)
- return 0;
-
- if ( strcmp( token, "gametype") != 0) {
- REPORT_ERROR(( stderr, "Unknown config command \"%s\"", token));
- return -1;
- }
-
- game_type= next_token_dup();
- if ( game_type == NULL) {
- REPORT_ERROR(( stderr, "Missing game type"));
- return -1;
- }
-
- force_lower_case( game_type);
-
- token= next_token();
- if ( token == NULL) {
- REPORT_ERROR(( stderr, "Expecting \"new\" or \"modify\""));
- return -1;
- }
-
- if ( strcmp( token, "new") == 0) {
- parse_func= pf_gametype_new;
- }
- else if ( strcmp( token, "modify") == 0) {
- parse_func= pf_gametype_modify;
- }
- else {
- REPORT_ERROR(( stderr, "Expecting \"new\" or \"modify\""));
- return -1;
- }
-
- context= (GameTypeContext*) malloc( sizeof(GameTypeContext));
- context->type= game_type;
- context->extend_type= NULL;
- context->gametype= NULL;
-
- token= next_token();
-
- if ( parse_func == pf_gametype_modify) {
- if ( token != NULL) {
- REPORT_ERROR(( stderr, "Extra text after gametype modify"));
- return -1;
- }
- context->gametype= get_server_type( game_type);
- if ( context->gametype == NULL) {
- REPORT_ERROR(( stderr, "Unknown game type \"%s\"", game_type));
- free(context);
- return -1;
- }
- parse_context= context;
- return 0;
- }
-
- if ( token == NULL || strcmp( token, "extend") != 0) {
- REPORT_ERROR(( stderr, "Expecting \"extend\""));
- return -1;
- }
-
- extend_type= next_token();
-
- if ( extend_type == NULL) {
- REPORT_ERROR(( stderr, "Missing extend game type"));
- return -1;
- }
-
- force_lower_case( extend_type);
-
- if ( strcasecmp( extend_type, game_type) == 0) {
- REPORT_ERROR(( stderr, "Identical game type and extend type"));
- return -1;
- }
-
- context->extend_type= extend_type;
- extend= get_server_type( extend_type);
- if ( extend == NULL) {
- REPORT_ERROR(( stderr, "Unknown extend game type \"%s\"", extend_type));
- return -1;
- }
-
- /* Over-write a previous gametype new */
- context->gametype= get_config_type( game_type);
- if ( context->gametype == NULL)
- context->gametype= (server_type*) malloc( sizeof(server_type));
- copy_server_type( context->gametype, extend);
-
- /* Set flag for new type-id if not re-defining previous config type */
- if ( get_config_type( game_type) == NULL)
- context->gametype->id= 0;
-
- context->gametype->type_string= game_type;
- context->gametype->type_prefix= strdup(game_type);
- force_upper_case( context->gametype->type_prefix);
- context->gametype->type_option= (char*)malloc( strlen(game_type)+2);
- context->gametype->type_option[0]= '-';
- strcpy( &context->gametype->type_option[1], game_type);
-
- parse_context= context;
-
- return 0;
- }
-
- STATIC int
- pf_gametype_modify( char *text, void *_context)
- {
- GameTypeContext *context= (GameTypeContext*) _context;
- char *token;
- int key;
-
- token= first_token( text);
- if ( token == NULL)
- return 0;
-
- if ( strcmp( token, "end") == 0) {
- parse_func= pf_top_level;
- parse_context= NULL;
- return 0;
- }
-
- key= get_config_key( token, modify_keys);
-
- token= next_token();
-
- if ( strcmp( token, "=") != 0) {
- REPORT_ERROR(( stderr, "Expecting \"=\", found \"%s\"", token));
- return -1;
- }
-
- token= next_value();
- if ( token == NULL) {
- REPORT_ERROR(( stderr, "Missing value after \"=\""));
- return -1;
- }
-
- if ( debug)
- printf( "%d %s = <%s>\n", key, modify_keys[key-1].key_name,
- token?token:"");
-
- return modify_game_type_value( context->gametype, key, token);
- }
-
- STATIC int
- pf_gametype_new( char *text, void *_context)
- {
- GameTypeContext *context= (GameTypeContext*) _context;
- char *token;
- int key;
-
- token= first_token( text);
- if ( token == NULL)
- return 0;
-
- if ( strcmp( token, "end") == 0) {
- add_config_type( context->gametype);
- parse_func= pf_top_level;
- parse_context= NULL;
- return 0;
- }
-
- key= get_config_key( token, new_keys);
-
- if ( key <= 0)
- return key;
-
- token= next_token();
- if ( strcmp( token, "=") != 0) {
- REPORT_ERROR(( stderr, "Expecting \"=\", found \"%s\"", token));
- return -1;
- }
-
- token= next_value();
- if ( token == NULL && (key != CK_MASTER_PROTOCOL && key != CK_MASTER_QUERY)) {
- REPORT_ERROR(( stderr, "Missing value after \"=\""));
- return -1;
- }
-
- if ( debug)
- printf("%d %s = <%s>\n", key, new_keys[key-1].key_name, token?token:"");
-
- return set_game_type_value( context->gametype, key, token);
- }
-
- STATIC int
- get_config_key( char *first_token, ConfigKey *keys)
- {
- char key_name[1024], *token;
- int key= 0;
-
- strcpy( key_name, first_token);
- do {
- int k;
- for ( k= 0; keys[k].key_name; k++) {
- if ( strcmp( keys[k].key_name, key_name) == 0) {
- key= keys[k].key;
- break;
- }
- }
- if ( key)
- break;
- token= next_token();
- if ( token == NULL || strcmp( token, "=") == 0)
- break;
- if ( strlen(key_name) + strlen(token) > sizeof(key_name)-2) {
- REPORT_ERROR(( stderr, "Key name too long"));
- return -1;
- }
- strcat( key_name, " ");
- strcat( key_name, token);
- } while ( 1);
-
- if ( key == 0) {
- REPORT_ERROR(( stderr, "Unknown config key \"%s\"", key_name));
- return -1;
- }
-
- return key;
- }
-
- STATIC int
- set_game_type_value( server_type *gametype, int key, char *value)
- {
- switch ( key) {
- case CK_NAME:
- gametype->game_name= strdup(value);
- break;
- case CK_DEFAULT_PORT: {
- unsigned short port;
- if ( sscanf( value, "%hu", &port) != 1) {
- REPORT_ERROR(( stderr, "Syntax error on port. Should be a number between 1 and 65535."));
- return -1;
- }
- gametype->default_port= port;
- break;
- }
- case CK_GAME_RULE:
- gametype->game_rule= strdup(value);
- break;
- case CK_TEMPLATE_VAR:
- gametype->template_var= strdup(value);
- force_upper_case( gametype->template_var);
- break;
- case CK_MASTER_PROTOCOL:
- if ( ! gametype->master) {
- REPORT_ERROR((stderr, "Cannot set master protocol on non-master game type\n"));
- return -1;
- }
- if ( value)
- gametype->master_protocol= strdup(value);
- else
- gametype->master_protocol= NULL;
- break;
- case CK_MASTER_QUERY:
- if ( ! gametype->master) {
- REPORT_ERROR((stderr, "Cannot set master query on non-master game type\n"));
- return -1;
- }
- if ( value)
- gametype->master_query= strdup(value);
- else
- gametype->master_query= NULL;
- break;
- case CK_MASTER_TYPE:
- {
- server_type *type;
- if ( ! gametype->master) {
- REPORT_ERROR((stderr, "Cannot set master type on non-master game type\n"));
- return -1;
- }
- force_lower_case( value);
- type= get_server_type( value);
- if ( type == NULL) {
- REPORT_ERROR((stderr, "Unknown server type \"%s\"\n", value));
- return -1;
- }
- gametype->master= type->id;
- }
- break;
- case CK_MASTER_PACKET:
- if ( ! gametype->master) {
- REPORT_ERROR((stderr, "Cannot set master packet on non-master game type"));
- return -1;
- }
- if ( value == NULL || value[0] == '\0') {
- REPORT_ERROR((stderr, "Empty master packet"));
- return -1;
- }
- gametype->master_packet= memdup( value, value_len);
- gametype->master_len= value_len;
- break;
- case CK_STATUS_PACKET:
- return set_packet_value( gametype, value, "status",
- &gametype->status_packet, &gametype->status_len);
- case CK_STATUS2_PACKET:
- return set_packet_value( gametype, value, "status2",
- &gametype->rule_packet, &gametype->rule_len);
- case CK_PLAYER_PACKET:
- return set_packet_value( gametype, value, "player",
- &gametype->player_packet, &gametype->player_len);
- case CK_RULE_PACKET:
- return set_packet_value( gametype, value, "rule",
- &gametype->rule_packet, &gametype->rule_len);
- case CK_PORT_OFFSET: {
- short port;
- if ( sscanf( value, "%hd", &port) != 1) {
- REPORT_ERROR(( stderr, "Syntax error on port. Should be a number between 32767 and -32768."));
- return -1;
- }
- gametype->port_offset= port;
- break;
- }
- }
-
- return 0;
- }
-
- STATIC int
- set_packet_value( server_type *gametype, char *value, char *packet_name,
- char **packet, int *len)
- {
- if ( gametype->master) {
- REPORT_ERROR((stderr, "Cannot set info packet on master game type"));
- return -1;
- }
- if ( value == NULL || value[0] == '\0') {
- REPORT_ERROR((stderr, "Empty %s packet", packet_name));
- return -1;
- }
- if ( *packet == NULL) {
- REPORT_ERROR((stderr, "Cannot set %s packet; extend game type does not define a %s packet", packet_name, packet_name));
- return -1;
- }
- *packet= memdup( value, value_len);
- *len= value_len;
- return 0;
- }
-
- STATIC int
- modify_game_type_value( server_type *gametype, int key, char *value)
- {
- switch ( key) {
- case CK_MASTER_PROTOCOL:
- if ( ! gametype->master) {
- REPORT_ERROR((stderr, "Cannot set master protocol on non-master game type"));
- return -1;
- }
- if ( value)
- gametype->master_protocol= strdup(value);
- else
- gametype->master_protocol= NULL;
- break;
- case CK_MASTER_QUERY:
- if ( ! gametype->master) {
- REPORT_ERROR((stderr, "Cannot set master query on non-master game type"));
- return -1;
- }
- if ( value)
- gametype->master_query= strdup(value);
- else
- gametype->master_query= NULL;
- break;
- case CK_MASTER_PACKET:
- if ( ! gametype->master) {
- REPORT_ERROR((stderr, "Cannot set master packet on non-master game type"));
- return -1;
- }
- if ( value == NULL || value[0] == '\0') {
- REPORT_ERROR((stderr, "Empty master packet"));
- return -1;
- }
- gametype->master_packet= memdup( value, value_len);
- break;
- }
- return 0;
- }
-
- STATIC server_type *
- get_server_type( char *game_type)
- {
- server_type *result;
- result= find_server_type_string( game_type);
- if ( result != NULL)
- return result;
-
- return get_config_type( game_type);
- }
-
- STATIC void
- add_config_type( server_type *gametype)
- {
- if ( gametype->id == 0) {
- if ( next_gametype_id >= MASTER_SERVER) {
- REPORT_ERROR(( stderr, "Exceeded game type limit, ignoring \"%s\"",
- gametype->type_string));
- return;
- }
- gametype->id= next_gametype_id;
- if ( gametype->master)
- gametype->id |= MASTER_SERVER;
- next_gametype_id++;
- }
-
- if ( max_config_types == 0) {
- max_config_types= 4;
- config_types= (server_type**) malloc(sizeof(server_type*) * (max_config_types + 1));
- }
- else if ( n_config_types >= max_config_types) {
- max_config_types*= 2;
- config_types= (server_type**) realloc( config_types,
- sizeof(server_type*) * (max_config_types + 1));
- }
- config_types[ n_config_types]= gametype;
- n_config_types++;
- }
-
- STATIC server_type *
- get_config_type( char *game_type)
- {
- server_type **search= config_types;
- int i;
- for ( i= 0; i < n_config_types; i++)
- if ( strcmp( config_types[i]->type_string, game_type) == 0)
- return config_types[i];
-
- return NULL;
- }
-
- STATIC void
- copy_server_type( server_type *dest, server_type *source)
- {
- *dest= *source;
- }
-
- STATIC void *
- memdup( void *mem, unsigned int len)
- {
- void *result= malloc( len);
- memcpy( result, mem, len);
- return result;
- }
-
- /* Parsing primitives
- */
-
- STATIC char *
- first_token( char *text)
- {
- parse_text= text;
- parse_end= parse_text + strlen( parse_text);
- lex= text;
- token_end= text;
-
- if ( *lex == '#')
- return NULL;
-
- return get_token();
- }
-
- STATIC char *
- next_token()
- {
- lex= token_end;
- return get_token();
- }
-
- STATIC char *
- next_token_dup()
- {
- return strdup( next_token());
- }
-
- STATIC char *
- get_token()
- {
- char *token= &token_buf[0];
- while ( isspace(*token_end))
- token_end++;
-
- if ( token_end == parse_end)
- return NULL;
-
- while ( (isalnum(*token_end) || *token_end == '.' || *token_end == '_' || *token_end == '-')
- && token < &token_buf[0] + sizeof(token_buf))
- *token++= *token_end++;
-
- if ( token == &token_buf[0])
- *token++= *token_end++;
- *token= '\0';
- return &token_buf[0];
- }
-
- extern void print_packet( struct qserver *server, char *buf, int buflen);
-
- STATIC char *
- next_value()
- {
- char *token= &token_buf[0];
- while ( isspace(*token_end))
- token_end++;
-
- if ( token_end == parse_end)
- return NULL;
-
- while ( token_end < parse_end && token < &token_buf[0] + sizeof(token_buf))
- *token++= *token_end++;
-
- *token--= '\0';
-
- if ( strchr( token_buf, '\\'))
- return parse_value(token_buf, (token - token_buf)+1);
-
- while ( isspace(*token))
- *token--= '\0';
-
- value_len= token - token_buf + 1;
-
- return &token_buf[0];
- }
-
- STATIC char *
- parse_value( char *source, int len)
- {
- char *value, *v, *end;
- int error= 0, rc;
- unsigned int n;
-
- value= (char*)malloc( len + 1);
- v= value;
-
- /*
- printf( "parse_value <%.*s>\n", len, source);
- */
-
- for ( ; len; len--, source++) {
- if ( *source != '\\') {
- *v++= *source;
- if ( *source != ' ')
- end= v;
- continue;
- }
- source++; len--;
- if ( len == 0)
- break;
- if ( *source == '\\')
- *v++= *source;
- else if ( *source == 'n')
- *v++= '\n';
- else if ( *source == 'r')
- *v++= '\r';
- else if ( *source == ' ')
- *v++= ' ';
- else if ( *source == 'x') {
- source++; len--;
- if ( len < 2)
- break;
- *v++= parse_hex(source, 2, &error);
- if ( error)
- break;
- source++; len--;
- }
- else if ( isdigit( *source)) {
- if ( len < 3)
- break;
- *v++= parse_oct(source, 3, &error);
- if ( error)
- break;
- source++; len--;
- source++; len--;
- }
- else {
- error= 1;
- REPORT_ERROR(( stderr, "Invalid character escape \"%.*s\"", 2,
- source-1));
- break;
- }
- end= v;
- }
-
- if ( error) {
- free(value);
- return NULL;
- }
-
- value_len= end - value;
- memcpy( token_buf, value, value_len);
- token_buf[value_len]= '\0';
-
- /*
- print_packet(NULL, token_buf, value_len);
- */
-
- free(value);
- return &token_buf[0];
- }
-
- STATIC unsigned int
- parse_hex( char *hex, int len, int *error)
- {
- char *save_hex= hex;
- int save_len= len;
- unsigned int result= 0;
- *error= 0;
- for ( ; len; len--, hex++) {
- result <<= 4;
- if ( ! isxdigit( *hex)) {
- *error= 1;
- REPORT_ERROR(( stderr, "Invalid hex \"%.*s\"", save_len+2,
- save_hex-2));
- return 0;
- }
- if ( *hex >= '0' && *hex <= '9')
- result|= *hex - '0';
- else if ( *hex >= 'A' && *hex <= 'F')
- result|= ((*hex - 'A') + 10);
- else if ( *hex >= 'a' && *hex <= 'f')
- result|= ((*hex - 'a') + 10);
- }
- return result;
- }
-
- STATIC unsigned int
- parse_oct( char *oct, int len, int *error)
- {
- char *save_oct= oct;
- int save_len= len;
- unsigned int result= 0;
- *error= 0;
- for ( ; len; len--, oct++) {
- result <<= 3;
- if ( *oct >= '0' && *oct <= '7')
- result|= *oct - '0';
- else {
- *error= 1;
- REPORT_ERROR(( stderr, "Invalid octal \"%.*s\"", save_len+1,
- save_oct-1));
- return 0;
- }
- }
- return result;
- }
-
- STATIC char *
- force_lower_case( char *string)
- {
- char *s= string;
- for ( ; *s; s++)
- *s= tolower(*s);
- return string;
- }
-
- STATIC char *
- force_upper_case( char *string)
- {
- char *s= string;
- for ( ; *s; s++)
- *s= toupper(*s);
- return string;
- }
-
-